#define PrynInternal
#define PrynImplementation
#include "platform.h"

void *prynStatePlatformPlatform ()
{
	PrynStateWindows *platform;
	HANDLE heap;
	
	heap = HeapCreate (0, 0, 0);
	if (!heap) return 0;
	platform = (PrynStateWindows *) HeapAlloc (heap, 0, sizeof (PrynStateWindows));
	platform->heap = heap;
	return platform;
}

PrynResult prynDefaultPrintFunction (PrynState *state, const PrynString *text)
{
	HANDLE handle = GetStdHandle (STD_OUTPUT_HANDLE);
	DWORD written;
	
	if (!text) return PrynResultNullArgument;
	if (handle) WriteFile (handle, text->pointer, text->length, &written, 0);
	return 0;
}

static PrynResult FileReadFunction (PrynStream *stream, void *output, size_t length, size_t *read, void *data)
{
	if (!ReadFile (stream->pProprietary, output, length, read, 0))
		return PrynResultExternalFailure;
	return PrynResultSuccess;
}

static PrynResult FileWriteFunction (PrynStream *stream, const void *output, size_t length, size_t *written, void *data)
{
	if (!WriteFile (stream->pProprietary, output, length, written, 0))
		return PrynResultExternalFailure;
	return PrynResultSuccess;
}

static PrynResult FileCloseFunction (PrynStream *stream, void *data)
{
	if (stream->pProprietary)
		CloseHandle (stream->pProprietary);
	return PrynResultSuccess;
}

PrynExport (PrynResult, prynStreamOpenFile, (PrynStream **output, PrynState *state, const PrynString *filename, bool read, bool write))
{
	PrynStartFunctionHasState ();
	PrynStream *stream = 0;
	const char *filenamez = 0;
	HANDLE handle = INVALID_HANDLE_VALUE;

	if (output) *output = 0;
	prynAssert (output && state && filename, NullArgument);
	prynAssert (read || write, BadArgument);
	prynCall (prynStringToZ (filename, state, &filenamez));
	prynCall (prynStreamCreate (&stream, state));

	handle = CreateFileA (filenamez, (read ? GENERIC_READ : 0) | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE, 0, read ? OPEN_EXISTING : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
	prynAssert (handle != INVALID_HANDLE_VALUE, ExternalFailure);

	if (read) stream->pReadFunction = &FileReadFunction;
	if (write) stream->pWriteFunction = &FileWriteFunction;
	stream->pCloseFunction = &FileCloseFunction;
	stream->pProprietary = handle;

	PrynEndFunctionAfter ({ // success
		*output = stream;
	}, { // failure
		prynStreamClose (stream);
		if (handle != INVALID_HANDLE_VALUE) CloseHandle (handle);
	}, { // common
		prynStringFreeZ (filename, state, filenamez);
	});
}